home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
muzsrc1.zip
/
DISPLAY.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-21
|
17KB
|
483 lines
// **********************************************
// File: DISPLAY.CPP
// The display module
#include "muzika.h"
#include <stdio.h>
#include <string.h>
#include <values.h>
HWND hEditWnd; // The edit window handle
HCURSOR hEditCursor; // The handle of the edit window cursor
int currStaffHeight; // Height of the currently displayed staff
STAFFLOC staffLoc; // Current staff location within multiple
int staffX, staffY; // Coordinates of the current staff
int scoreMultiplicity, scoreStaves; // Parameters for the score display
int scoreFirstStaff, scoreFirstPart; // Parameters for the score display
// **********************************************
// Following are the Edit window functions
// **********************************************
// RegisterEditClass registers the Edit window class
// during the first-instance initialization (called by
// InitMainFirst in MAIN.CPP).
void RegisterEditClass(HANDLE hInstance)
{
WNDCLASS wc;
// Register the edit window class
wc.lpszClassName = "MUZIKA_edit";
wc.hInstance = hInstance;
wc.lpfnWndProc = EditWindowProc;
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = COLOR_APPWORKSPACE+1;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClass(&wc);
}
// **********************************************
// CreateEditWindow creates and displays an edit window
// (this is the window where the edited score is displayed).
void CreateEditWindow(HANDLE hInstance)
{
// Get the main window extents
RECT mainExt;
GetClientRect(hMainWnd, &mainExt);
// Create and display the edit window
hEditWnd = CreateWindow("MUZIKA_edit",
NULL,
WS_CHILDWINDOW | WS_VSCROLL,
73, 37,
mainExt.right-72, mainExt.bottom-36,
hMainWnd,
NULL,
hInstance,
NULL);
ShowScrollBar(hEditWnd, SB_VERT, FALSE);
ShowWindow(hEditWnd, SW_SHOWNA);
// Set the initial cursor
hEditCursor = LoadCursor(NULL, IDC_ARROW);
}
// **********************************************
// EditWindowProc is the edit window procedure, which responds to messages
// intended for the edit window. The messages processed are described within.
long FAR PASCAL EditWindowProc(
HWND hWnd, unsigned message, WORD wParam, LONG lParam)
{
static int Xfrom, Xto, Y, Yfrom, Yto;
static enum {NEWCONTINUOUS, MOVEOBJECT, MOVESTAFF} capture;
// Check message type
switch(message) {
case WM_PAINT:
// Process a WM_PAINT message, indicating that the window
// should be repainted.
PaintEditWindow(hWnd);
break;
case WM_MOUSEMOVE:
// Process a WM_MOUSEMOVE message, indicating that the cursor
// has moved in the edit window region; the cursor shape should
// be changed to the current symbol shape.
SetCursor(hEditCursor);
break;
case WM_LBUTTONDOWN:
// Process a WM_LBUTTONDOWN message, indicating that the user
// has clicked the left mouse button. According to what the
// current edit symbol is, an editing action is performed.
if (melodyExists)
if (!scoreDisplay)
switch (GetActiveSymbol()) {
case PENCIL:
// The current symbol is the pencil on a staff:
// insert a new staff at the current position
NewMultipleStaff(MAKEPOINT(lParam).y);
break;
case ERASER:
// The current symbol is the eraser:
// erase the symbols at the current cursor position
DeleteMusicalObject(MAKEPOINT(lParam).x, MAKEPOINT(lParam).y);
break;
case HAND:
// The current symbol is the hand:
// capture the mouse until the left button is released,
// then move the objects to their new place.
Xfrom = MAKEPOINT(lParam).x;
Yfrom = MAKEPOINT(lParam).y;
SetCapture(hEditWnd);
capture = MOVEOBJECT;
break;
default:
// The current symbol is one of the musical object symbols:
// insert the appropriate object at the current position
SymbolClass *currentSymbol = GetCurrentSymbol();
switch (currentSymbol->GetType()) {
case POINTOBJECT:
// The symbol corresponds to a point object:
// just insert the object in the staff
NewPointObject(currentSymbol,
MAKEPOINT(lParam).x, MAKEPOINT(lParam).y);
break;
case CONTINUOUSOBJECT:
// The symbol corresponds to a continuous object:
// capture the mouse until the left button is released,
// then create the object between its two extents.
Xfrom = MAKEPOINT(lParam).x;
Y = MAKEPOINT(lParam).y;
SetCapture(hEditWnd);
capture = NEWCONTINUOUS;
break;
}
}
else
// No editing is allowed on a score display
MessageBox(hWnd, "Cannot edit a score display", NULL,
MB_ICONSTOP | MB_OK);
break;
case WM_LBUTTONUP:
// Process a WM_LBUTTONUP message, indicating that the
// left mouse button has been released. In case the mouse cursor
// was captured (presumably because of an operation that required
// two points to operate), release the capture and complete
// the operation.
if (GetCapture() == hEditWnd) {
switch (capture) {
case NEWCONTINUOUS:
// The capture was due to insertion of a continuous object:
// insert a new continuous object between the two points
Xto = MAKEPOINT(lParam).x;
if (Xto < Xfrom) {
int temp = Xto;
Xto = Xfrom;
Xfrom = temp;
}
if (Xto != Xfrom)
NewContinuousObject(GetCurrentSymbol(), Xfrom, Xto, Y);
break;
case MOVEOBJECT:
// The capture was due to an object moving operation:
// move a musical object to its new place
Xto = MAKEPOINT(lParam).x;
Yto = MAKEPOINT(lParam).y;
MoveMusicalObject(Xfrom, Yfrom, Xto, Yto);
break;
case MOVESTAFF:
// The capture was due to a staff moving operation:
// move the staff to its new place
Yto = MAKEPOINT(lParam).y;
MoveStaff(Yfrom, Yto);
break;
}
ReleaseCapture();
}
break;
case WM_LBUTTONDBLCLK:
// Process a WM_LBUTTONDBLCLK, indicating that the user has
// double-clicked the left mouse button. According to what the
// current edit symbol is, an editing action is performed.
if (melodyExists)
if (!scoreDisplay)
switch(GetActiveSymbol()) {
case ERASER:
// The current symbol is the eraser:
// erase the multiple staff
DeleteMultipleStaff(MAKEPOINT(lParam).y);
break;
case HAND:
// The current symbol is the hand:
// capture the mouse until the left button is released,
// then move the staff to its new place.
Yfrom = MAKEPOINT(lParam).y;
SetCapture(hEditWnd);
capture = MOVESTAFF;
break;
}
break;
case WM_VSCROLL:
// Process a WM_VSCROLL message, indicating that the user
// has clicked on the scroll bar. The screen should be updated
// according to the new position of the scroll bar thumb.
unsigned newY = GetScrollPos(hEditWnd, SB_VERT);
int minScroll, maxScroll;
GetScrollRange(hEditWnd, SB_VERT, &minScroll, &maxScroll);
RECT editRect;
GetClientRect(hEditWnd, &editRect);
// Process the various possibilities of the scroll bar notification
switch (wParam) {
case SB_BOTTOM:
SetScrollPos(hEditWnd, SB_VERT, maxScroll, TRUE);
break;
case SB_LINEDOWN:
SetScrollPos(hEditWnd, SB_VERT,
newY+(scoreDisplay ? 1 : pixelsPerStaff), TRUE);
break;
case SB_LINEUP:
SetScrollPos(hEditWnd, SB_VERT,
newY-(scoreDisplay ? 1 : pixelsPerStaff), TRUE);
break;
case SB_PAGEDOWN:
SetScrollPos(hEditWnd, SB_VERT,
newY+editRect.bottom/(scoreDisplay ? pixelsPerStaff : 1), TRUE);
break;
case SB_PAGEUP:
SetScrollPos(hEditWnd, SB_VERT,
newY-editRect.bottom/(scoreDisplay ? pixelsPerStaff : 1), TRUE);
break;
case SB_THUMBPOSITION:
SetScrollPos(hEditWnd, SB_VERT, LOWORD(lParam), TRUE);
break;
case SB_TOP:
SetScrollPos(hEditWnd, SB_VERT, 0, TRUE);
break;
case SB_ENDSCROLL:
if (scoreDisplay)
scoreFirstStaff = newY;
else
((Part *) &melody.part[displayedPart])->SetPartY(newY);
InvalidateRect(hEditWnd, NULL, TRUE);
break;
}
break;
default:
// Unrecognized message: just let Windows take care of it.
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0L;
}
// **********************************************
// PaintEditWindow is the edit window painting function,
// activated whenever the edit window receives a WM_PAINT message.
// It redraws the edit window, including staves and objects.
void PaintEditWindow(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hDC;
// Obtain a display context
hDC = BeginPaint(hWnd, &ps);
// Draw the page according to the current settings
if (melodyExists) {
if (!scoreDisplay) {
// Display a single part
Part &p = *((Part *) &melody.part[displayedPart]);
int firstStaff = 0, lastStaff = 0;
// Display the page
for (int index = 0; index < p.staff.number(); ++index) {
int firstY, lastY;
if (index % p.multiplicity() == 0) {
firstY = -1;
lastY = MAXINT-24;
}
Staff &s = *((Staff *) &p.staff[index]);
// Draw the staff itself
if (s.Draw(hDC, p.GetPartY(), TRUE)) {
if (!firstStaff) firstStaff = index+p.multiplicity();
lastStaff = index+p.multiplicity();
staffX = s.X();
staffY = s.Y()-p.GetPartY();
// Check whether first or last staff in a group
staffLoc = MIDSTAFF;
if (index % p.multiplicity() == 0) {
firstY = staffY;
staffLoc = FIRSTSTAFF;
}
if ((index+1) % p.multiplicity() == 0) {
lastY = staffY;
staffLoc = LASTSTAFF;
}
if (p.multiplicity() == 1)
staffLoc = SINGLESTAFF;
currStaffHeight = (index+1 < p.staff.number()) ?
((Staff *) &p.staff[index+1])->Y()-s.Y() : pixelsPerStaff;
// Draw the point objects inside the staff
IndexedList &pointList = s.pointObject;
for (int i = 0; i < pointList.number(); ++i)
((PointObject *) &pointList[i])->Draw(hDC);
// Draw the continuous objects inside the staff
IndexedList &contList = s.continuousObject;
for (i = 0; i < contList.number(); ++i)
((ContinuousObject *) &contList[i])->Draw(hDC);
}
// Check if the multiple staff is complete
if ((index+1)%p.multiplicity() == 0) {
if (firstY != -1 || lastY != MAXINT-24) {
// Draw the connecting lines of a multiple staff
MoveTo(hDC, s.X(), firstY);
LineTo(hDC, s.X(), lastY+24);
MoveTo(hDC, s.X()+s.width()-1, firstY);
LineTo(hDC, s.X()+s.width()-1, lastY+24);
}
// Show the marked block
int i = index/p.multiplicity()*p.multiplicity();
if (i >= markBeginStaff && i <= markEndStaff) {
int markFrom, markTo;
if (i == markBeginStaff)
markFrom = markBeginX-pixelsPerObject/2;
if (i > markBeginStaff)
markFrom = 0;
if (i == markEndStaff)
markTo = markEndX+pixelsPerObject/2;
if (i < markEndStaff)
markTo = s.width();
PatBlt(hDC, markFrom+s.X(),
((Staff *) &p.staff[i])->Y()-p.GetPartY(),
markTo-markFrom, s.Y()+25-((Staff *) &p.staff[i])->Y(),
DSTINVERT);
}
}
}
// Display the status information
char strnum[15];
HDC hStatusDC = GetDC(hMainWnd);
HBRUSH hBrush, hOldBrush;
hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
hOldBrush = SelectObject(hStatusDC, hBrush);
Rectangle(hStatusDC, 108, -1, GetSystemMetrics(SM_CXSCREEN), 37);
SetBkColor(hStatusDC, GetSysColor(COLOR_WINDOW));
SetTextAlign(hStatusDC, TA_UPDATECP);
MoveTo(hStatusDC, 110, 2);
TextOut(hStatusDC, 0, 0, "Current part: ", 14);
TextOut(hStatusDC, 0, 0, p.name(), strlen(p.name()));
TextOut(hStatusDC, 0, 0, ", Staves ", 9);
sprintf(strnum, "%d-%d",
firstStaff/p.multiplicity(), lastStaff/p.multiplicity());
TextOut(hStatusDC, 0, 0, strnum, strlen(strnum));
SelectObject(hStatusDC, hOldBrush);
DeleteObject(hBrush);
ReleaseDC(hMainWnd, hStatusDC);
}
else {
// Display score
int line = 0;
int staffLeftX = 32;
int staffRightX = 32+melody.GetStaffWidth();
BOOL screenFull = FALSE;
for (int scoreIndex = scoreFirstStaff;
scoreIndex < scoreStaves && !screenFull; ++scoreIndex) {
// Draw a multiple staff
for (int partIndex = scoreFirstPart; partIndex < melody.part.number();
++partIndex) {
Part &p = *((Part *) &melody.part[partIndex]);
for (int staffIndex = scoreIndex*p.multiplicity();
staffIndex < (scoreIndex+1)*p.multiplicity(); ++staffIndex) {
// Draw a single staff
Staff &s = *((Staff *) &p.staff[staffIndex]);
int tempY = s.Y();
s.Y() = line += pixelsPerStaff;
screenFull = !s.Draw(hDC, 0, TRUE);
staffX = staffLeftX;
staffY = line;
// Draw the point objects inside the staff
IndexedList &pointList = s.pointObject;
for (int i = 0; i < pointList.number(); ++i)
((PointObject *) &pointList[i])->Draw(hDC);
// Draw the continuous objects inside the staff
IndexedList &contList = s.continuousObject;
for (i = 0; i < contList.number(); ++i)
((ContinuousObject *) &contList[i])->Draw(hDC);
s.Y() = tempY;
}
}
// Draw the connecting lines of the score multiple staff
MoveTo(hDC, staffLeftX, line-(scoreMultiplicity-1)*pixelsPerStaff);
LineTo(hDC, staffLeftX, line+24);
MoveTo(hDC, staffRightX, line-(scoreMultiplicity-1)*pixelsPerStaff);
LineTo(hDC, staffRightX, line+24);
}
// Display the status information
char strnum[15];
HDC hStatusDC = GetDC(hMainWnd);
HBRUSH hBrush, hOldBrush;
hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
hOldBrush = SelectObject(hStatusDC, hBrush);
Rectangle(hStatusDC, 108, -1, GetSystemMetrics(SM_CXSCREEN), 37);
SetBkColor(hStatusDC, GetSysColor(COLOR_WINDOW));
SetTextAlign(hStatusDC, TA_UPDATECP);
MoveTo(hStatusDC, 110, 2);
TextOut(hStatusDC, 0, 0, "Score display, Staff ", 21);
sprintf(strnum, "%d", scoreFirstStaff+1);
TextOut(hStatusDC, 0, 0, strnum, strlen(strnum));
SelectObject(hStatusDC, hOldBrush);
DeleteObject(hBrush);
ReleaseDC(hMainWnd, hStatusDC);
}
}
EndPaint(hWnd, &ps);
}
// **********************************************
// Staff::Draw is the Staff class's Draw function,
// which draws a staff in a display context, returning TRUE
// if the staff was not entirely clipped.
BOOL Staff :: Draw(HDC hDC, int editYMin, BOOL clip)
{
int line = Y();
RECT staffRect = {0, line-editYMin, melody.GetStaffWidth(), line-editYMin+24};
RECT windowRect, dummyRect;
// Check whether staff is within screen range
if (clip) GetClientRect(hEditWnd, &windowRect);
if (!clip || IntersectRect(&dummyRect, &staffRect, &windowRect)) {
// Either no clip checking or the staff is within clipping boundaries:
// draw the staff lines
for (; line < Y()+5*6; line += 6 ) {
MoveTo(hDC, X(), line-editYMin);
LineTo(hDC, X()+width(), line-editYMin);
}
return TRUE;
}
return FALSE;
}